﻿//using IoTAdapter.BaseCore.Enums;
using IoTAdapter.BaseCore;
using IoTAdapter.BaseCore.Enums;
using IoTAdapter.Clients.Andon;
using Microsoft.Extensions.Logging;
using Polly;
using SqlSugar;
using WCS.Entities.Enum;

namespace WCS.Entities
{
    public class TransferPort : Facilities
    {

        #region Property

        /// <summary>
        /// 料口所属设备的Id
        /// </summary>
        public string DeviceId { get; set; }

        /// <summary>
        /// AGV状态寄存器地址
        /// </summary>
        public string AgvAddress { get; set; }

        /// <summary>
        /// PLC状态寄存器地址
        /// </summary>
        public string PlcAddress { get; set; }

        /// <summary>
        /// AGV状态值
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public short AgvValue { get; set; }

        /// <summary>
        /// PLC状态值
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public short PlcValue { get; set; }

        /// <summary>
        /// 是否在呼叫
        /// </summary>
        public PortStatus Status { set; get; }

        /// <summary>
        /// 位置编号
        /// </summary>
        public string LocationNumber { get; set; }

        public string Content { get; set; }

        /// <summary>
        /// 优先级
        /// </summary>
        public int Priority { get; set; }

        /// <summary>
        /// 当前任务呼叫类型
        /// </summary>
        public TaskType CallType { get; set; } = Entities.TaskType.None;

        /// <summary>
        /// 展示信息
        /// </summary>
        [SugarColumn(IsIgnore = true)]
        public Dictionary<string, int> PLcDisplayInfo { get; set; } = new Dictionary<string, int>();

        /// <summary>
        /// 展示信息
        /// </summary>
        [SugarColumn(IsIgnore = true)]
        public Dictionary<string, int> AgvDisplayInfo { get; set; } = new Dictionary<string, int>();


        [SugarColumn(IsJson = true)]
        public List<TaskType> TaskType { get; set; }

        /// <summary>
        /// 所属设备
        /// </summary>
        [Navigate(NavigateType.ManyToOne, nameof(DeviceId))]
        public Device BelongDevice { get; set; }

        [SugarColumn(IsNullable = true)]
        public string Remark { get; set; }

        public int Capacity { get; set; } = 1;
        public int CurrentNumber { get; set; }

        [SugarColumn(IsNullable = true)]
        public string Palletnumber { get; set; }

        public bool IsFull => CurrentNumber == Capacity;
        /// <summary>
        /// 是否锁住
        /// </summary>
        public bool Locked { get; set; }=false;
        #endregion

        #region 重写Equal

        #region Method


        /// <summary>
        /// 将AGV寄存器某一位置位，并检测
        /// </summary>
        /// <param name="index">需要置位并检测的位（0-15）</param>
        /// <param name="robotIp">当前对接设备的机器人ip可以为空或者any</param>
        /// <param name="logger">日志接口</param>
        /// <returns></returns>
        public bool CheckRealAgvValue(ushort index, string robotIp, ILogger logger)
        {
            if (!(BelongDevice?.Operation?.IsConnected ?? false))
                return false;

            var currentAgvResult = BelongDevice.Operation.ReadInt16(AgvAddress);

            if (!currentAgvResult.IsSucceed)
                logger.LogWarning("The robot ({0}) notice target ({1}) get real value of AgvAdress {2}  Bit{3} failed!", robotIp, Name, AgvAddress, index);

            if (!BitHelper.GetBitValue(currentAgvResult.Value, index))
            {
                var writeValue = BitHelper.SetBitValue(currentAgvResult.Value, index, true);

                if (!BelongDevice.Operation.Write(AgvAddress, (short)writeValue).IsSucceed)
                {
                    logger.LogWarning("The robot ({0}) notice target ({1}) write AgvAdress {2} to Bit{3} failed!", robotIp, Name, AgvAddress, index);
                    return false;
                }
                else
                {
                    logger.LogInformation("The robot ({0}) notice target ({1}) write AgvAdress {2} to Bit{3} success!", robotIp, Name, AgvAddress, index);
                    return true;

                }
            }
            return true;
        }

        /// <summary>
        /// 异步将AGV寄存器某一位置位，并检测
        /// </summary>
        /// <param name="index">需要置位并检测的位（0-15）</param>
        /// <param name="robotIp">当前对接设备的机器人ip可以为空或者any</param>
        /// <param name="logger">日志接口</param>
        /// <returns></returns>
        public async Task<bool> CheckRealAgvValueAsync(ushort index, string robotIp, ILogger logger)
        {
            if (!(BelongDevice?.Operation?.IsConnected ?? false))
                return false;

            var currentAgvResult = await BelongDevice.Operation.ReadInt16Async(AgvAddress);

            if (!currentAgvResult.IsSucceed)
                logger.LogWarning("The robot ({0}) notice target ({1}) get real value of AgvAdress {2}  Bit{3} failed!", robotIp, Name, AgvAddress, index);

            if (!BitHelper.GetBitValue(currentAgvResult.Value, index))
            {
                var writeValue = BitHelper.SetBitValue(currentAgvResult.Value, index, true);

                if (!(await BelongDevice.Operation.WriteAsync(AgvAddress, (short)writeValue)).IsSucceed)
                {
                    logger.LogWarning("The robot ({0}) notice target ({1}) write AgvAdress {2} to Bit{3} failed!", robotIp, Name, AgvAddress, index);
                    return false;
                }
                else
                {
                    logger.LogInformation("The robot ({0}) notice target ({1}) write AgvAdress {2} to Bit{3} success!", robotIp, Name, AgvAddress, index);
                    return true;

                }
            }
            return true;
        }


        /// <summary>
        /// 检测plc寄存器某一位置位是否为1
        /// </summary>
        /// <param name="index">需要置位并检测的位（0-15）</param>
        /// <param name="robotIp">当前对接设备的机器人ip可以为空或者any</param>
        /// <param name="logger">日志接口</param>
        /// <returns></returns>
        public bool CheckRealPlcValue(ushort index, string robotIp, ILogger logger)
        {
            if (!(BelongDevice?.Operation?.IsConnected ?? false))
                return false;

            var currentPLCResult = BelongDevice.Operation.ReadInt16(PlcAddress);
            //检查PLC值
            if (!currentPLCResult.IsSucceed)
            {
                logger.LogWarning("The robot ({0}) notice target ({1}) get real value of PlcAdress {2}  Bit{3} failed!", robotIp, Name, AgvAddress, index);
                return false;
            }
            logger.LogInformation("The robot{0} notice target-{1} get the plcValue({2}) is:{3}-({4})", robotIp, Name, PlcAddress, currentPLCResult.Value, Convert.ToString(currentPLCResult.Value, 2));
            return BitHelper.GetBitValue(currentPLCResult.Value, index);
        }

        /// <summary>
        /// 异步检测plc寄存器某一位置位是否为1
        /// </summary>
        /// <param name="index">需要置位并检测的位（0-15）</param>
        /// <param name="robotIp">当前对接设备的机器人ip可以为空或者any</param>
        /// <param name="logger">日志接口</param>
        /// <returns></returns>
        public async Task<bool> CheckRealPlcValueAsync(ushort index, string robotIp, ILogger logger)
        {
            if (!(BelongDevice?.Operation?.IsConnected ?? false))
                return false;
            var currentPLCResult = await BelongDevice.Operation.ReadInt16Async(PlcAddress);
            if (!currentPLCResult.IsSucceed)
            {
                logger.LogWarning("The robot ({0}) notice target ({1}) get real value of PlcAdress {2}  Bit{3} failed!", robotIp, Name, AgvAddress, index);
                return false;
            }
            logger.LogInformation("The robot{0} notice target-{1} get the plcValue({2}) is:{3}-({4})", robotIp, Name, PlcAddress, currentPLCResult.Value, Convert.ToString(currentPLCResult.Value, 2));
            return BitHelper.GetBitValue(currentPLCResult.Value, index);
        }

        /// <summary>
        /// 回应任务呼叫
        /// </summary>
        /// <param name="targetValue"></param>
        /// <returns></returns>
        public bool ResponseCall()
        {
            if (BelongDevice.Type == EthernetDeviceVersion.CallButton)
            {
                return true;
            }
            if (BelongDevice.Type == EthernetDeviceVersion.AndonKitClient)
            {
                return BelongDevice.Operation.Write(AgvAddress, (byte)LightColor.Green).IsSucceed;
            }
            if (BelongDevice.MonitorType == "Stacker")
            {
                var noiceAddress = AgvAddress == "22"? "" : "";
                return BelongDevice.Operation.Write(noiceAddress, true).IsSucceed;
            }
            else
            {
                if (AgvValue == 0)
                {
                    return BelongDevice.Operation.Write(AgvAddress, (short)1).IsSucceed;
                }
                else
                {
                    return BitHelper.GetBitValue(AgvValue, 0);
                }
            }
        }

        public async void ReSet(ILogger logger)
        {
            await Policy.HandleResult<Result>(x => x.IsSucceed == false)
             .WaitAndRetryAsync(
                6,
             retryAttempt => TimeSpan.FromSeconds(Math.Pow(1.5, retryAttempt))).ExecuteAsync(() =>
             {
                 if (AgvValue == 0)
                     return Task.FromResult(new Result());
                 logger.LogInformation("Try to reset the port ({0}-{1}) to 0", Id, AgvAddress);
                 return BelongDevice?.Operation?.WriteAsync(AgvAddress, (short)0);
             }
            );
        }
        #endregion

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            if (ReferenceEquals(obj, this))
            {
                return true;
            }

            return obj is TransferPort b && Id == (obj as TransferPort).Id;
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }
        #endregion
    }
}
